전처리 | 연속형 자료의 범위 조정

preprocessing
Author

강신성

Published

2023-10-22

sklearn.preprocessing을 이용하여 자료의 범위를 전처리해보자.

해당 자료는 전북대학교 통계학과 최규빈 교수님의 강의 내용을 토대로 재구성되었음을 밝힙니다.

1. 라이브러리 import

import pandas as pd
import numpy as np
import sklearn.preprocessing

2. MinMaxScaler

A. 모티브


- 예제자료 : 학점, 토익 등이 취업에 미치는 정도

df = pd.read_csv('https://raw.githubusercontent.com/guebin/MP2023/main/posts/employment.csv').loc[:7,['toeic','gpa']]
df
toeic gpa
0 135 0.051535
1 935 0.355496
2 485 2.228435
3 65 1.179701
4 445 3.962356
5 65 1.846885
6 290 0.309928
7 730 0.336081

- 모형을 돌려보고 해석한 결과… (sklearn.linear_model.Linear_Regression())

u = X.toeic*0.00571598 + X.gpa*2.46520018 -8.45433334
v = 1/(1+np.exp(-u))
v # 확률같은것임

그래서… * 토익이 중요해? 아니면 학점이 중요해? * 무엇이 얼만큼 중요해?

- 모티브 : 토익과 gpa 모두 0~1 사이의 척도로 바꾸면 해석이 쉽지 않을까?

### B. 사용방법

  • class를 이용, object를 생성하는 방법(이전과 유사한 방법)
scalr = sklearn.preprocessing.MinMaxScaler()

scalr.fit(df)

scalr.transform(df)  ## 전처리의 경우에는 transform을 사용한다. .impute.SimpleImputer()에서도 그랬잖아?
array([[0.08045977, 0.        ],
       [1.        , 0.07772319],
       [0.48275862, 0.55663499],
       [0.        , 0.28847292],
       [0.43678161, 1.        ],
       [0.        , 0.45907256],
       [0.25862069, 0.06607128],
       [0.76436782, 0.07275881]])
  • 역시 한번에 할 수도 있다.
scalr.fit_transform(df)  ## 당연히 원래 자료를 훼손하진 않는다.
array([[0.08045977, 0.        ],
       [1.        , 0.07772319],
       [0.48275862, 0.55663499],
       [0.        , 0.28847292],
       [0.43678161, 1.        ],
       [0.        , 0.45907256],
       [0.25862069, 0.06607128],
       [0.76436782, 0.07275881]])
sklearn.preprocessing.minmax_scale(df)  ## 한 번에 할 수도 있다.
array([[0.08045977, 0.        ],
       [1.        , 0.07772319],
       [0.48275862, 0.55663499],
       [0.        , 0.28847292],
       [0.43678161, 1.        ],
       [0.        , 0.45907256],
       [0.25862069, 0.06607128],
       [0.76436782, 0.07275881]])

위처럼 할 수도 있는데, 이 경우는 scalr를 test셋에 적용시킬 수 없기 때문에 사용하지 않는다.

C. 옳고 그른 방법론


# 1 비효율적인 전환

- 주어진 자료가 아래와 같이 train/test로 나뉘어있다고 하자.

X = np.array([1.0, 2.0, 3.0, 4.0, 5.0]).reshape(-1,1)
XX = np.array([1.5, 2.5, 3.5]).reshape(-1,1)

X, XX
(array([[1.],
        [2.],
        [3.],
        [4.],
        [5.]]),
 array([[1.5],
        [2.5],
        [3.5]]))
scalr = sklearn.preprocessing.MinMaxScaler()

scalr.fit_transform(X), scalr.fit_transform(XX)
(array([[0.  ],
        [0.25],
        [0.5 ],
        [0.75],
        [1.  ]]),
 array([[0. ],
        [0.5],
        [1. ]]))

같은 값임에도 다르게 스케일을 변환시키는 것을 볼 수 있다.(X에선 5가 1인데, XX에선 3.5가 1이 됨.

# 2 권장하는 스케일링 방법

scalr = sklearn.preprocessing.MinMaxScaler()

scalr.fit(X)

scalr.transform(X), scalr.transform(XX)
(array([[0.  ],
        [0.25],
        [0.5 ],
        [0.75],
        [1.  ]]),
 array([[0.125],
        [0.375],
        [0.625]]))

더 합리적이다.

# 3 변환값의 범위

- 변환한 값이 무조건 0과 1 사이가 되는 것은 아니다.

X = np.array([1.0, 2.0, 3.0, 4.0, 3.5]).reshape(-1,1)
XX = np.array([1.5, 2.5, 5.0]).reshape(-1,1)
## XX의 5.0은 X에서의 최대값인 4.0을 초과한다.
sclr = sklearn.preprocessing.MinMaxScaler()
sclr.fit(X)

sclr.transform(X), sclr.transform(XX)
(array([[0.        ],
        [0.33333333],
        [0.66666667],
        [1.        ],
        [0.83333333]]),
 array([[0.16666667],
        [0.5       ],
        [1.33333333]]))

스케일링한 값이 1보다 커질 수 있다.

### D. 아주아주 잘못된 스케일링 방법 - 정보누수

- 주어진 자료가 아래와 같다고 하자.

X = np.array([1.0, 2.0, 3.0, 4.0, 3.5]).reshape(-1,1)
XX = np.array([1.5, 2.5, 5.0]).reshape(-1,1)

- train data와 test data를 합친다….????!!!??!?!??

np.concatenate([X, XX], axis = 0)
array([[1. ],
       [2. ],
       [3. ],
       [4. ],
       [3.5],
       [1.5],
       [2.5],
       [5. ]])

- 합친 데이터에서 스케일링….

sklearn.preprocessing.MinMaxScaler().fit_transform(np.concatenate([X, XX], axis = 0))
array([[0.   ],
       [0.25 ],
       [0.5  ],
       [0.75 ],
       [0.625],
       [0.125],
       [0.375],
       [1.   ]])

이렇게 전저리하는 것은 정보누수에 해당한다. 본래 test dataset은 알지 못한 상태인데 그것을 합칠 순 없다!

대회에서 이런 일이 발생하면 cheating으로 간주되어 탈락된다.

  • 위에서 minmax_scale()로 처리하는 것은 전략적으로 비효율적인 문제이지 치팅과 관련된 치명적인 문제가 아니다. (만약 어떠한 경우에 minmax_scale 전처리 방식이 유리하다는 생각이 들면 사용해도 무방함)

3. StandardScaler

df = pd.read_csv('https://raw.githubusercontent.com/guebin/MP2023/main/posts/employment.csv').loc[:7,['toeic','gpa']]
df
toeic gpa
0 135 0.051535
1 935 0.355496
2 485 2.228435
3 65 1.179701
4 445 3.962356
5 65 1.846885
6 290 0.309928
7 730 0.336081

여기서 토익과 gpa가 미치는 영향을 비교하기 위해 각 값들을 표준화해보자.

A. 사용법


sclr = sklearn.preprocessing.StandardScaler()
sclr.fit_transform(df)
array([[-0.8680409 , -0.98104887],
       [ 1.81575704, -0.73905505],
       [ 0.3061207 ,  0.75205327],
       [-1.10287322, -0.08287854],
       [ 0.17193081,  2.13248542],
       [-1.10287322,  0.44828929],
       [-0.34805505, -0.77533368],
       [ 1.12803382, -0.75451182]])

MinMaxScaler도 마찬가지로 여러 열을 한번에 할 수 있다.

- 원리

(df.toeic - df.toeic.mean())/df.toeic.std(ddof=0) # 계산식, 자유도는 0(모분산으로 취급)
0   -0.868041
1    1.815757
2    0.306121
3   -1.102873
4    0.171931
5   -1.102873
6   -0.348055
7    1.128034
Name: toeic, dtype: float64

그냥 표준화하는 것

4. 비교

- MinMaxScalerStandardScaler는 데이터의 스케일을 조정하는 두 가지 일반적인 방법이다.

  1. MinMaxSclaer:
    • 장점 : 원하는 범위 내로 데이터를 조정할 때 유용, 특히 신경망에서는 활성화 함수의 범위와 일치하도록 입력값을 조정하는 데 유용.
    • 단점 : 이상치에 매우 민감하다.
  2. StandardScaler:
    • 장점 : 이상치에 덜 민감함, 많은 통계적 기법들 - 선형 알고리즘에서 잘 작동
    • 단점 : 표준화된 데이터의 값이 특정 범위 내에 있음을 보장하지 않음.

단순히 MinMaxScaler는 데이터가 0~1 또는 -1~1사이의 범위에 있다고 가정한다.

그래서 둘 중 어느 것을 선택해야 하는데???

  • 둘 중 이상치가 많으면 StandardScaler가 더 적합할 수 있다.
  • 모델의 알고리즘과 특성에 따라 선택해야 한다. 신경망의 경우 MinMaxScaler가 적합할 수 있다.

결론적으로 두 스케일링 방법 중 어느 것이 더 좋은지는 사용 사례와 데이터의 특성에 따라 다르기 때문에, 가능한 경우 둘 다 시도해보고 모델의 성능을 비교하는 것이 좋다.

결론

답이 없다!